package net.lulihu.common_util.validated;

import net.lulihu.ObjectKit.*;
import net.lulihu.exception.ExceptionEnum;
import net.lulihu.exception.ParamResolveException;
import net.lulihu.exception.ToolBoxException;
import org.apache.commons.lang3.reflect.FieldUtils;

import javax.validation.Valid;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Collection;

/**
 * 参数检查工具
 */
public class ParamValidated {

    /**
     * 检查对象中的参数，需要在参数的属性上指定对应注解进行对应的参数校验
     * 不匹配时抛出 参数不合法异常（默认异常）
     * <p>
     * 如果属性上注解定义异常信息，则抛出指定异常信息
     *
     * @param obj 检查对象
     */
    public static void examine(Object obj) {
        examine(obj, new ParamResolveException());
    }

    /**
     * 检查对象中的参数，需要在参数的属性上指定对应注解进行对应的参数校验
     *
     * @param obj           检查对象
     * @param exceptionEnum 不匹配时抛出指定异常
     */
    public static void examine(Object obj, ExceptionEnum exceptionEnum) {
        try {
            for (Field field : ReflectKit.getAllFieldsList(obj.getClass())) {
                Annotation[] anns = field.getAnnotations();
                Object value = FieldUtils.readField(field, obj, true);
                for (Annotation ann : anns) {
                    // 内部验证
                    if (ann instanceof Valid)
                        validated(value);
                    else
                        AnnotationValidated.examine(ann, value, exceptionEnum);
                }
            }
        } catch (IllegalAccessException e) {
            throw new ToolBoxException(e);
        }
    }

    /**
     * 内部验证序列
     *
     * @param value 值
     */
    private static void validated(Object value) {
        if (ObjectKit.hasEmpty(value)) return;

        // 集合
        if (value instanceof Collection) {
            for (Object obj : (Collection) value) {
                examine(obj);
            }
            //  bean对象
        } else if (BeanKit.isBean(value.getClass())) {
            examine(value);
        }
    }

    /**
     * 如果为true 则抛出指定参数异常信息
     *
     * @param boo           判断
     * @param exceptionEnum 异常信息
     */
    public static void isTrue(boolean boo, ExceptionEnum exceptionEnum) {
        if (boo)
            throw new ParamResolveException(exceptionEnum);
    }

    /**
     * 如果为true 则抛出参数异常信息
     *
     * @param boo 判断
     */
    public static void isTrue(boolean boo) {
        if (boo)
            throw new ParamResolveException();
    }

    /**
     * 参数组不允许存在空参数
     * <p>
     * 空参数的定义如下<br>
     * 不为null
     * 1、String 不为"" or " " <br>
     * 2、List,Set,Map,Object[],int[],long[] 长度大于0
     *
     * @param exceptionEnum 错误信息
     * @param params        参数 【可多个】
     * @throws ParamResolveException 为空将抛出请求参数异常
     */
    public static void isNotEmpty(ExceptionEnum exceptionEnum, Object... params) {
        isNotEmpty(exceptionEnum, null, params);
    }

    /**
     * 参数组不允许存在空参数
     * <p>
     * 空参数的定义如下<br>
     * 不为null
     * 1、String 不为"" or " " <br>
     * 2、List,Set,Map,Object[],int[],long[] 长度大于0
     *
     * @param exceptionEnum 错误信息
     * @param errorMessage  错误异常信息 如果异常信息不为空，则抛出指定异常信息
     * @param params        参数 【可多个】
     */
    public static void isNotEmpty(ExceptionEnum exceptionEnum, String errorMessage, Object... params) {
        boolean isEmpty = isOneEmpty(params);
        if (isEmpty)
            throwException(errorMessage, exceptionEnum);
    }

    /**
     * 参数组不允许存在空参数
     * <p>
     * 空参数的定义如下<br>
     * 不为null
     * 1、String 不为"" or " " <br>
     * 2、List,Set,Map,Object[],int[],long[] 长度大于0
     *
     * @param params 参数 【可多个】
     * @throws ParamResolveException 为空将抛出请求参数异常
     */
    public static void isNotEmpty(Object... params) {
        isNotEmpty(new ParamResolveException(), params);
    }

    /**
     * 参数组必须全部为空
     * <p>
     * 空的定义如下<br>
     * 1、为null <br>
     *
     * @param exceptionEnum 错误信息
     * @param params        参数
     */
    public static void isEmpty(ExceptionEnum exceptionEnum, Object... params) {
        boolean isEmpty = isAllEmpty(params);
        if (!isEmpty)
            throwException(null, exceptionEnum);
    }

    /**
     * 参数必须为空
     * <p>
     * 空的定义如下<br>
     * 1、为null <br>
     *
     * @param params 参数
     */
    public static void isEmpty(Object... params) {
        isEmpty(new ParamResolveException(), params);
    }

    /**
     * 对象是否为空
     * <p>
     * 空参数的定义如下<br>
     * 1、String 不为"" or " " <br>
     * 2、List,Set,Map,Object[],int[],long[] 长度大于0
     *
     * @param param 校验对象
     * @return 不为空则为true  反之false
     */
    public static boolean hasNotEmpty(Object... param) {
        return !isOneEmpty(param);
    }


    /**
     * 对象组中是否存在空对象
     *
     * @param os 对象组
     * @return 有一个为空则为true 反之false
     */
    public static boolean isOneEmpty(Object... os) {
        for (Object o : os) {
            if (ObjectKit.hasEmpty(o))
                return true;
        }
        return false;
    }

    /**
     * 对象组中是否全部为空
     */
    public static boolean isAllEmpty(Object... os) {
        for (Object o : os) {
            if (!ObjectKit.hasEmpty(o)) {
                return false;
            }
        }
        return true;
    }


    /**
     * 判断字符串是否存在于指定字符串组中
     * <p>
     * 有一个为空则为true 反之false
     *
     * @param str 字符串 字符串为null，则为false
     * @param os  字符串组
     * @return 有一个为空则为true 反之false
     */
    public static boolean isOneExist(String str, String[] os) {
        if (ObjectKit.hasEmpty(str) || CollectionKit.isEmpty(os)) return false;
        for (String o : os) {
            if (str.equals(o))
                return true;
        }
        return false;
    }

    /**
     * 判断数值是否存在于指定数值组中
     * <p>
     * 有一个为空则为true 反之false
     *
     * @param str 数值 字符串为null，则为false
     * @param os  字数值组
     * @return 有一个为空则为true 反之false
     */
    public static boolean isOneExist(Number str, Number[] os) {
        if (ObjectKit.hasEmpty(str) || CollectionKit.isEmpty(os)) return false;
        for (Number o : os) {
            if (str.equals(o))
                return true;
        }
        return false;
    }

    /**
     * 抛出异常信息
     *
     * @param errorMessage     异常信息 如果该字符串不为空，则抛出该异常信息，反之抛出 默认异常信息
     * @param defaultException 默认异常信息
     */
    public static void throwException(String errorMessage, ExceptionEnum defaultException) {
        if (StrKit.isNotEmpty(errorMessage))
            throw new ParamResolveException(errorMessage);
        else if (defaultException instanceof ParamResolveException)
            throw (ParamResolveException) defaultException;
        throw new ParamResolveException(defaultException);
    }

}
